home *** CD-ROM | disk | FTP | other *** search
/ Aminet 49 / Aminet 49 (2002)(GTI - Schatztruhe)[!][Jun 2002].iso / Aminet / util / libs / ttrender.lha / ttrender-2.0 / Developer / source / base / ftdbgmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-06  |  15.4 KB  |  673 lines

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  ftdbgmem.c                                                             */
  4. /*                                                                         */
  5. /*    Memory debugger (body).                                              */
  6. /*                                                                         */
  7. /*  Copyright 2001 by                                                      */
  8. /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
  9. /*                                                                         */
  10. /*  This file is part of the FreeType project, and may only be used,       */
  11. /*  modified, and distributed under the terms of the FreeType project      */
  12. /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  13. /*  this file you indicate that you have read the license and              */
  14. /*  understand and accept it fully.                                        */
  15. /*                                                                         */
  16. /***************************************************************************/
  17.  
  18.  
  19. #include <ft2build.h>
  20. #include FT_CONFIG_CONFIG_H
  21. #include FT_INTERNAL_DEBUG_H
  22. #include FT_INTERNAL_MEMORY_H
  23. #include FT_SYSTEM_H
  24. #include FT_ERRORS_H
  25. #include FT_TYPES_H
  26.  
  27.  
  28. #ifdef FT_DEBUG_MEMORY
  29.  
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34.  
  35.  
  36.   typedef struct FT_MemNodeRec_*   FT_MemNode;
  37.   typedef struct FT_MemTableRec_*  FT_MemTable;
  38.  
  39. #define FT_MEM_VAL( addr )  ((FT_ULong)(FT_Pointer)( addr ))
  40.  
  41.   typedef struct  FT_MemNodeRec_
  42.   {
  43.     FT_Byte*     address;
  44.     FT_Long      size;     /* < 0 if the block was freed */
  45.  
  46.    const char*  alloc_file_name;
  47.     FT_Long      alloc_line_no;
  48.  
  49.    const char*  free_file_name;
  50.     FT_Long      free_line_no;
  51.  
  52.     FT_MemNode   link;
  53.  
  54.  } FT_MemNodeRec;
  55.  
  56.  
  57.   typedef struct  FT_MemTableRec_
  58.   {
  59.     FT_ULong         size;
  60.     FT_ULong         nodes;
  61.     FT_MemNode*      buckets;
  62.  
  63.     FT_ULong         alloc_total;
  64.     FT_ULong         alloc_current;
  65.     FT_ULong         alloc_max;
  66.  
  67.    const char*      file_name;
  68.     FT_Long          line_no;
  69.  
  70.     FT_Memory        memory;
  71.    FT_Pointer       memory_user;
  72.     FT_Alloc_Func    alloc;
  73.     FT_Free_Func     free;
  74.     FT_Realloc_Func  realloc;
  75.  
  76.  } FT_MemTableRec;
  77.  
  78.  
  79. #define FT_MEM_SIZE_MIN  7
  80. #define FT_MEM_SIZE_MAX  13845163
  81.  
  82. #define FT_FILENAME( x )  ((x) ? (x) : "unknown file")
  83.  
  84.  
  85.   static const FT_UInt  ft_mem_primes[] =
  86.   {
  87.     7,
  88.     11,
  89.     19,
  90.     37,
  91.     73,
  92.     109,
  93.     163,
  94.     251,
  95.     367,
  96.     557,
  97.     823,
  98.     1237,
  99.     1861,
  100.     2777,
  101.     4177,
  102.     6247,
  103.     9371,
  104.     14057,
  105.     21089,
  106.     31627,
  107.     47431,
  108.     71143,
  109.     106721,
  110.     160073,
  111.     240101,
  112.     360163,
  113.     540217,
  114.     810343,
  115.     1215497,
  116.     1823231,
  117.     2734867,
  118.     4102283,
  119.     6153409,
  120.     9230113,
  121.     13845163,
  122.   };
  123.  
  124.  
  125. #include <stdarg.h>
  126.  
  127.  
  128.   extern void
  129.   ft_mem_debug_panic( const char*  fmt, ... )
  130.   {
  131.     va_list  ap;
  132.  
  133.  
  134.     printf( "FreeType.Debug: " );
  135.  
  136.     va_start( ap, fmt );
  137.     vprintf( fmt, ap );
  138.     va_end( ap );
  139.  
  140.     printf( "\n" );
  141.     exit( EXIT_FAILURE );
  142.   }
  143.  
  144.  
  145.   static FT_ULong
  146.   ft_mem_closest_prime( FT_ULong  num )
  147.   {
  148.     FT_UInt  i;
  149.  
  150.  
  151.     for ( i = 0;
  152.           i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
  153.       if ( ft_mem_primes[i] > num )
  154.         return ft_mem_primes[i];
  155.  
  156.     return FT_MEM_SIZE_MAX;
  157.   }
  158.  
  159.  
  160.   static FT_Pointer
  161.   ft_mem_table_alloc( FT_MemTable  table,
  162.                       FT_Long      size )
  163.   {
  164.     FT_Memory   memory = table->memory;
  165.     FT_Pointer  block;
  166.  
  167.  
  168.     memory->user = table->memory_user;
  169.     block = table->alloc( memory, size );
  170.     memory->user = table;
  171.  
  172.    return block;
  173.   }
  174.  
  175.  
  176.   static void
  177.   ft_mem_table_free( FT_MemTable  table,
  178.                      FT_Pointer   block )
  179.   {
  180.     FT_Memory  memory = table->memory;
  181.  
  182.  
  183.     memory->user = table->memory_user;
  184.     table->free( memory, block );
  185.     memory->user = table;
  186.   }
  187.  
  188.  
  189.   static void
  190.   ft_mem_table_resize( FT_MemTable  table )
  191.   {
  192.     FT_ULong  new_size;
  193.  
  194.  
  195.     new_size = ft_mem_closest_prime( table->nodes );
  196.     if ( new_size != table->size )
  197.     {
  198.       FT_MemNode*  new_buckets ;
  199.       FT_ULong     i;
  200.  
  201.  
  202.       new_buckets = ft_mem_table_alloc( table,
  203.                                         new_size * sizeof ( FT_MemNode ) );
  204.       if ( new_buckets == NULL )
  205.         return;
  206.  
  207.       MEM_Set( new_buckets, 0, sizeof ( FT_MemNode ) * new_size );
  208.  
  209.       for ( i = 0; i < table->size; i++ )
  210.       {
  211.         FT_MemNode  node, next, *pnode;
  212.         FT_ULong    hash;
  213.  
  214.  
  215.         node = table->buckets[i];
  216.         while ( node )
  217.         {
  218.           next  = node->link;
  219.           hash  = FT_MEM_VAL( node->address ) % new_size;
  220.           pnode = new_buckets + hash;
  221.  
  222.           node->link = pnode[0];
  223.           pnode[0]   = node;
  224.  
  225.           node = next;
  226.         }
  227.       }
  228.  
  229.       if ( table->buckets )
  230.         ft_mem_table_free( table, table->buckets );
  231.  
  232.       table->buckets = new_buckets;
  233.       table->size    = new_size;
  234.     }
  235.   }
  236.  
  237.  
  238.   static FT_MemTable
  239.   ft_mem_table_new( FT_Memory  memory )
  240.   {
  241.     FT_MemTable  table;
  242.  
  243.  
  244.     table = memory->alloc( memory, sizeof ( *table ) );
  245.     if ( table == NULL )
  246.       goto Exit;
  247.  
  248.     MEM_Set( table, 0, sizeof ( *table ) );
  249.  
  250.     table->size  = FT_MEM_SIZE_MIN;
  251.     table->nodes = 0;
  252.  
  253.     table->memory = memory;
  254.  
  255.     table->memory_user = memory->user;
  256.  
  257.     table->alloc   = memory->alloc;
  258.     table->realloc = memory->realloc;
  259.     table->free    = memory->free;
  260.  
  261.     table->buckets = memory->alloc( memory,
  262.                                     table->size * sizeof ( FT_MemNode ) );
  263.     if ( table->buckets )
  264.       MEM_Set( table->buckets, 0, sizeof ( FT_MemNode ) * table->size );
  265.     else
  266.     {
  267.       memory->free( memory, table );
  268.       table = NULL;
  269.     }
  270.  
  271.  Exit:
  272.     return table;
  273.   }
  274.  
  275.  
  276.   static void
  277.   ft_mem_table_destroy( FT_MemTable  table )
  278.   {
  279.     FT_ULong  i;
  280.  
  281.  
  282.     if ( table )
  283.     {
  284.       FT_Long    leak_count = 0;
  285.       FT_ULong   leaks = 0;
  286.  
  287.  
  288.       for ( i = 0; i < table->size; i++ )
  289.       {
  290.         FT_MemNode  *pnode = table->buckets + i, next, node = *pnode;
  291.  
  292.  
  293.         while ( node )
  294.         {
  295.           next       = node->link;
  296.           node->link = 0;
  297.  
  298.           if ( node->size > 0 )
  299.           {
  300.             printf(
  301.               "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
  302.               node->address, node->size,
  303.               FT_FILENAME( node->alloc_file_name ),
  304.               node->alloc_line_no );
  305.  
  306.             leak_count++;
  307.             leaks += node->size;
  308.  
  309.             ft_mem_table_free( table, node->address );
  310.           }
  311.  
  312.           node->address = NULL;
  313.           node->size    = 0;
  314.  
  315.           free( node );
  316.           node = next;
  317.         }
  318.         table->buckets[i] = 0;
  319.       }
  320.       ft_mem_table_free( table, table->buckets );
  321.       table->buckets = NULL;
  322.  
  323.       table->size   = 0;
  324.       table->nodes  = 0;
  325.       free( table );
  326.  
  327.       printf(
  328.         "FreeType: total memory allocations = %ld\n", table->alloc_total );
  329.       printf(
  330.         "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
  331.  
  332.       if ( leak_count > 0 )
  333.         ft_mem_debug_panic(
  334.           "FreeType: %ld bytes of memory leaked in %ld blocks\n",
  335.           leaks, leak_count );
  336.       printf( "FreeType: No memory leaks detected!\n" );
  337.     }
  338.   }
  339.  
  340.  
  341.   static FT_MemNode*
  342.   ft_mem_table_get_nodep( FT_MemTable  table,
  343.                           FT_Byte*     address )
  344.   {
  345.     FT_ULong     hash;
  346.     FT_MemNode  *pnode, node;
  347.  
  348.  
  349.     hash  = FT_MEM_VAL( address );
  350.     pnode = table->buckets + ( hash % table->size );
  351.  
  352.     for (;;)
  353.     {
  354.       node = pnode[0];
  355.       if ( !node )
  356.         break;
  357.  
  358.       if ( node->address == address )
  359.         break;
  360.  
  361.       pnode = &node->link;
  362.     }
  363.     return pnode;
  364.   }
  365.  
  366.  
  367.   static void
  368.   ft_mem_table_set( FT_MemTable  table,
  369.                     FT_Byte*     address,
  370.                     FT_ULong     size )
  371.   {
  372.     FT_MemNode  *pnode, node;
  373.  
  374.  
  375.     if ( table )
  376.     {
  377.       pnode = ft_mem_table_get_nodep( table, address );
  378.       node  = *pnode;
  379.       if ( node )
  380.       {
  381.         if ( node->size < 0 )
  382.         {
  383.           /* this block was already freed.  This means that our memory is */
  384.           /* now completely corrupted!                                    */
  385.           ft_mem_debug_panic(
  386.             "memory heap corrupted (allocating freed block)" );
  387.         }
  388.         else
  389.         {
  390.           /* this block was already allocated.  This means that our memory */
  391.           /* is also corrupted!                                            */
  392.           ft_mem_debug_panic(
  393.             "memory heap corrupted (re-allocating allocated block)" );
  394.         }
  395.       }
  396.  
  397.       /* we need to create a new node in this table */
  398.       node = ft_mem_table_alloc( table, sizeof ( *node ) );
  399.       if ( node == NULL )
  400.         ft_mem_debug_panic( "not enough memory to run memory tests" );
  401.  
  402.       node->address = address;
  403.       node->size    = size;
  404.  
  405.       node->alloc_file_name = table->file_name;
  406.       node->alloc_line_no   = table->line_no;
  407.  
  408.       node->free_file_name = NULL;
  409.       node->free_line_no   = 0;
  410.  
  411.       node->link = pnode[0];
  412.  
  413.       pnode[0] = node;
  414.       table->nodes++;
  415.  
  416.       table->alloc_total   += size;
  417.       table->alloc_current += size;
  418.       if ( table->alloc_current > table->alloc_max )
  419.         table->alloc_max = table->alloc_current;
  420.  
  421.       if ( table->nodes * 3 < table->size  ||
  422.            table->size  * 3 < table->nodes )
  423.         ft_mem_table_resize( table );
  424.     }
  425.   }
  426.  
  427.  
  428.   static void
  429.   ft_mem_table_remove( FT_MemTable  table,
  430.                        FT_Byte*     address )
  431.   {
  432.     if ( table )
  433.     {
  434.       FT_MemNode  *pnode, node;
  435.  
  436.  
  437.       pnode = ft_mem_table_get_nodep( table, address );
  438.       node  = *pnode;
  439.       if ( node )
  440.       {
  441.         if ( node->size < 0 )
  442.           ft_mem_debug_panic(
  443.             "freeing memory block at %p more than once at (%s:%ld)\n"
  444.             "block allocated at (%s:%ld) and released at (%s:%ld)",
  445.             address,
  446.             FT_FILENAME( table->file_name ), table->line_no,
  447.             FT_FILENAME( node->alloc_file_name ), node->alloc_line_no,
  448.             FT_FILENAME( node->free_file_name ), node->free_line_no );
  449.  
  450.         /* we simply invert the node's size to indicate that the node */
  451.         /* was freed.  We also change its contents.                   */
  452.         MEM_Set( address, 0xF3, node->size );
  453.  
  454.         table->alloc_current -= node->size;
  455.         node->size            = -node->size;
  456.         node->free_file_name  = table->file_name;
  457.         node->free_line_no    = table->line_no;
  458.       }
  459.       else
  460.         ft_mem_debug_panic(
  461.           "trying to free unknown block at %p in (%s:%ld)\n",
  462.           address,
  463.           FT_FILENAME( table->file_name ), table->line_no );
  464.     }
  465.   }
  466.  
  467.  
  468.   extern FT_Pointer
  469.   ft_mem_debug_alloc( FT_Memory  memory,
  470.                       FT_Long    size )
  471.   {
  472.     FT_MemTable  table = memory->user;
  473.     FT_Byte*     block;
  474.  
  475.  
  476.     if ( size <= 0 )
  477.       ft_mem_debug_panic( "negative block size allocation (%ld)", size );
  478.  
  479.     block = ft_mem_table_alloc( table, size );
  480.     if ( block )
  481.       ft_mem_table_set( table, block, (FT_ULong)size );
  482.  
  483.     table->file_name = NULL;
  484.     table->line_no   = 0;
  485.  
  486.     return (FT_Pointer) block;
  487.   }
  488.  
  489.  
  490.   extern void
  491.   ft_mem_debug_free( FT_Memory   memory,
  492.                      FT_Pointer  block )
  493.   {
  494.     FT_MemTable  table = memory->user;
  495.  
  496.  
  497.     if ( block == NULL )
  498.       ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
  499.                           FT_FILENAME( table->file_name ),
  500.                           table->line_no );
  501.  
  502.     ft_mem_table_remove( table, (FT_Byte*)block );
  503.  
  504.     /* we never really free the block */
  505.     table->file_name = NULL;
  506.     table->line_no   = 0;
  507.   }
  508.  
  509.  
  510.   extern FT_Pointer
  511.   ft_mem_debug_realloc( FT_Memory   memory,
  512.                         FT_Long     cur_size,
  513.                         FT_Long     new_size,
  514.                         FT_Pointer  block )
  515.   {
  516.     FT_MemTable  table = memory->user;
  517.     FT_MemNode   node, *pnode;
  518.     FT_Pointer   new_block;
  519.  
  520.     const char*  file_name = FT_FILENAME( table->file_name );
  521.     FT_Long      line_no   = table->line_no;
  522.  
  523.  
  524.     if ( block == NULL || cur_size == 0 )
  525.       ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
  526.                            file_name, line_no );
  527.  
  528.     if ( new_size <= 0 )
  529.       ft_mem_debug_panic(
  530.         "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
  531.         block, cur_size, file_name, line_no );
  532.  
  533.     /* check 'cur_size' value */
  534.     pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
  535.     node  = *pnode;
  536.     if ( !node )
  537.       ft_mem_debug_panic(
  538.         "trying to reallocate unknown block at %p in (%s:%ld)",
  539.         block, file_name, line_no );
  540.  
  541.     if ( node->size <= 0 )
  542.       ft_mem_debug_panic(
  543.         "trying to reallocate freed block at %p in (%s:%ld)",
  544.         block, file_name, line_no );
  545.  
  546.     if ( node->size != cur_size )
  547.       ft_mem_debug_panic( "invalid realloc request for %p. cur_size is "
  548.                           "%ld instead of %ld in (%s:%ld)",
  549.                           block, cur_size, node->size, file_name, line_no );
  550.  
  551.     new_block = ft_mem_debug_alloc( memory, new_size );
  552.     if ( new_block == NULL )
  553.       return NULL;
  554.  
  555.     memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
  556.  
  557.     table->file_name = file_name;
  558.     table->line_no   = line_no;
  559.  
  560.     ft_mem_debug_free( memory, (FT_Byte*)block );
  561.  
  562.     return new_block;
  563.   }
  564.  
  565.  
  566.   extern FT_Int
  567.   ft_mem_debug_init( FT_Memory  memory )
  568.   {
  569.     FT_MemTable  table;
  570.     FT_Int       result = 0;
  571.  
  572.  
  573.     if ( getenv( "FT_DEBUG_MEMORY" ) )
  574.     {
  575.       table = ft_mem_table_new( memory );
  576.       if ( table )
  577.       {
  578.         memory->user    = table;
  579.         memory->alloc   = ft_mem_debug_alloc;
  580.         memory->realloc = ft_mem_debug_realloc;
  581.         memory->free    = ft_mem_debug_free;
  582.         result = 1;
  583.       }
  584.     }
  585.     return result;
  586.   }
  587.  
  588.  
  589.   extern void
  590.   ft_mem_debug_done( FT_Memory  memory )
  591.   {
  592.     FT_MemTable  table = memory->user;
  593.  
  594.  
  595.     if ( table )
  596.     {
  597.       memory->free    = table->free;
  598.       memory->realloc = table->realloc;
  599.       memory->alloc   = table->alloc;
  600.  
  601.       ft_mem_table_destroy( table );
  602.       memory->user = NULL;
  603.     }
  604.   }
  605.  
  606.  
  607.   FT_BASE_DEF( FT_Error )
  608.   FT_Alloc_Debug( FT_Memory    memory,
  609.                   FT_Long      size,
  610.                   void*       *P,
  611.                   const char*  file_name,
  612.                   FT_Long      line_no )
  613.   {
  614.     FT_MemTable  table = memory->user;
  615.  
  616.  
  617.     if ( table )
  618.     {
  619.       table->file_name = file_name;
  620.       table->line_no   = line_no;
  621.     }
  622.     return FT_Alloc( memory, size, P );
  623.   }
  624.  
  625.  
  626.   FT_BASE_DEF( FT_Error )
  627.   FT_Realloc_Debug( FT_Memory    memory,
  628.                     FT_Long      current,
  629.                     FT_Long      size,
  630.                     void*       *P,
  631.                     const char*  file_name,
  632.                     FT_Long      line_no )
  633.   {
  634.     FT_MemTable  table = memory->user;
  635.  
  636.  
  637.     if ( table )
  638.     {
  639.       table->file_name = file_name;
  640.       table->line_no   = line_no;
  641.     }
  642.     return FT_Realloc( memory, current, size, P );
  643.   }
  644.  
  645.  
  646.   FT_BASE_DEF( void )
  647.   FT_Free_Debug( FT_Memory    memory,
  648.                  FT_Pointer   block,
  649.                  const char*  file_name,
  650.                  FT_Long      line_no )
  651.   {
  652.     FT_MemTable  table = memory->user;
  653.  
  654.  
  655.     if ( table )
  656.     {
  657.       table->file_name = file_name;
  658.       table->line_no   = line_no;
  659.     }
  660.     FT_Free( memory, block );
  661.   }
  662.  
  663.  
  664. #else  /* !FT_DEBUG_MEMORY */
  665.  
  666.   /* ANSI C doesn't like empty source files */
  667.   const FT_Byte  _debug_mem_dummy = 0;
  668.  
  669. #endif /* !FT_DEBUG_MEMORY */
  670.  
  671.  
  672. /* END */
  673.